package com.jdpc.weparty.security

import com.jdpc.weparty.component.ServerConfig
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@Component
class JwtAuthenticationTokenFilter : OncePerRequestFilter() {
    @Autowired
    private lateinit var userDetailsService: UserDetailsService

    @Autowired
    private lateinit var jwtTokenUtil: JwtTokenUtil

    @Autowired
    private lateinit var serverConfig: ServerConfig

    @Throws(ServletException::class, IOException::class)
    override fun doFilterInternal(
            request: HttpServletRequest,
            response: HttpServletResponse,
            chain: FilterChain) {
        val authHeader = request.getHeader(serverConfig.tokenHeader)
        if (authHeader != null && authHeader.startsWith(serverConfig.tokenHead)) {
            val authToken = authHeader.substring(serverConfig.tokenHead.length) // The part after "Bearer "
            val account = jwtTokenUtil.getAccountFromToken(authToken)
            logger.info("checking authentication $account")
            if (account != null && SecurityContextHolder.getContext().authentication == null) {

                val userDetails = userDetailsService.loadUserByUsername(account)
                if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    val authentication = UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.authorities)
                    authentication.details = WebAuthenticationDetailsSource().buildDetails(
                            request)
                    logger.info("authenticated user $account, setting security context")
                    SecurityContextHolder.getContext().authentication = authentication
                }
            }
        }
        chain.doFilter(request, response)
    }
}